/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						 combat_actor_model_definition.cpp

	$Header: /heroes4/combat_actor_model_definition.cpp $

	$NoKeywords: $

 ************************************************************************/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "combat_actor_model_definition.h"

#include "enum_operations.h"
#include "streambuf_operators.h"

// ------------------------------------------------------------------------------
// Unnamed namespace
// ------------------------------------------------------------------------------

namespace
{
	// ------------------------------------------------------------------------------
	// ------------------------------------------------------------------------------
	int const k_current_format_version = 6;

} // Unnamed namespace

// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
bool read( std::streambuf & stream, t_combat_actor_model_definition & definition )
{
	try
	{
		int version = get< t_uint16 >( stream );
		if ( version < 0 || version > k_current_format_version )
			return false;

		int footprint_size = get< t_uint8 >( stream );
		if ( version < 1 )
			footprint_size = t_combat_actor_model_definition::k_min_footprint_size;
		definition.set_footprint_size( footprint_size );

		int height;
		int prewalk;
		int postwalk;
		int walk;
		if ( version >= 2 )
			height = get< t_uint8 >( stream );
		else
			height = t_combat_actor_model_definition::k_min_height;
		if ( version >= 3 )
		{
			prewalk = get< t_uint16 >( stream );
			walk    = get< t_uint16 >( stream );
			postwalk = get<t_uint16>( stream );
		}
		else
		{
			prewalk  = 16;
			walk     = 64;
			postwalk = 16;
		}
		definition.set_height( height );
		definition.set_prewalk_length( prewalk );
		definition.set_walk_length( walk );
		definition.set_postwalk_length( postwalk );

		t_map_point_3d origin;
		t_direction    direction;

		if (version >= 6)
		{
			for (direction = t_direction(0); direction < k_direction_count;
			     enum_incr( direction ))
			{
				read( stream, &origin, sizeof( origin ));
				definition.set_missile_origin( direction, origin );
			}
		}
		else
		{
			origin.row = footprint_size / 2;
			origin.column = footprint_size / 2;
			origin.height = height / 2;
			for (direction = t_direction(0); direction < k_direction_count;
			     enum_incr( direction ))
				definition.set_missile_origin( direction, origin );
		}

		std::string action_name;
		int num_actions = get< t_uint16 >( stream );
		while ( num_actions > 0 )
		{
			--num_actions;

			// Read the action name
			stream >> action_name;

			int frames_per_second = get< t_uint8 >( stream );
			int key_frame = 0;

			if (version >= 5)
				key_frame = get<t_uint8>( stream );

			std::string sequence_name_array[ k_direction_count ];
			t_direction direction;
			for ( direction = t_direction( 0 ); direction < k_direction_count; enum_incr( direction ) )
				stream >> sequence_name_array[ direction ];

			// Map the action name to an action id
			t_combat_actor_action_id action_id;

			action_id = get_combat_action( action_name );
			if ( action_id >= k_combat_actor_action_count )
				continue;

			definition.set_frames_per_second( action_id, frames_per_second );
			definition.set_key_frame( action_id, key_frame );
			for ( direction = t_direction( 0 ); direction < k_direction_count; enum_incr( direction ) )
				definition.set_sequence_name( action_id, direction, sequence_name_array[ direction ] );
		}

		t_screen_point offset( 0, 0 );
		if ( version >= 4 )
			stream >> offset;
		definition.set_offset( offset );
	}
	catch ( t_streambuf_read_failure const & )
	{
		return false;
	}
	return true;
}

// ------------------------------------------------------------------------------
// ------------------------------------------------------------------------------
bool write( std::streambuf & stream, t_combat_actor_model_definition const & definition )
{
	try
	{
		put< t_uint16 >( stream, k_current_format_version );

		put< t_uint8 >( stream, definition.get_footprint_size() );
		put< t_uint8 >( stream, definition.get_height() );
		put< t_uint16 >( stream, definition.get_prewalk_length() );
		put< t_uint16 >( stream, definition.get_walk_length()  );
		put< t_uint16 >( stream, definition.get_postwalk_length() );

		t_direction direction;

		for (direction = t_direction(0); direction < k_direction_count; enum_incr( direction ))
			write( stream, &definition.get_missile_origin( direction ), 
			       sizeof( t_map_point_3d ));

		// Write the number of actions
		put< t_uint16 >( stream, k_combat_actor_action_count );

		t_combat_actor_action_id action_id;

		for ( action_id = t_combat_actor_action_id( 0 ); action_id < k_combat_actor_action_count; enum_incr( action_id ) )
		{
			stream << get_combat_actor_action_name( action_id );

			put< t_uint8 >( stream, definition.get_frames_per_second( action_id ) );
			put< t_uint8 >( stream, definition.get_key_frame( action_id ) );

			t_direction direction;
			for ( direction = t_direction( 0 ); direction < k_direction_count; enum_incr( direction ) )
				stream << definition.get_sequence_name( action_id, direction );
		}

		stream << definition.get_offset();
	}
	catch ( t_streambuf_write_failure const & )
	{
		return false;
	}
	return true;
}

// ------------------------------------------------------------------------------
// t_resource_traits< t_combat_actor_model_definition > members
// ------------------------------------------------------------------------------

char const t_resource_traits< t_combat_actor_model_definition >::prefix[] = "combat_actor";

char const t_resource_traits< t_combat_actor_model_definition >::extension[] = "cac";
